package com.wugh.fast.kernel.util.recursive;

import cn.hutool.core.collection.CollectionUtil;
import lombok.Getter;
import lombok.Setter;

import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 说明: 集合递归转化成流
 *
 * @author wugh
 * @date 2019-12-11 16:08
 */
public class StreamRecursive<T, R> extends DefaultRecursive<Collection<StreamRecursive.Box<T, R>>, Stream<R>> {
    /**
     * 获取下级的方法
     */
    protected Function<T, Collection<T>> childrenGetter;
    /**
     * 通过已有参数,转化成要的参数
     */
    protected Function<StreamRecursive.Box<T, R>, R> mapFunc;

    public StreamRecursive(Function<T, Collection<T>> childrenGetter, Function<StreamRecursive.Box<T, R>, R> mapFunc) {
        this.childrenGetter = childrenGetter;
        this.mapFunc = mapFunc;
        this.identity = Stream.empty();
        this.reduce = Stream::concat;
        this.function = collection -> collection.stream().map(box -> {
            R ret = mapFunc.apply(box);
            box.setRet(ret);
            return ret;
        }).filter(Objects::nonNull);
        this.test = (collection, stream) -> collection.stream().anyMatch(any -> CollectionUtil.isNotEmpty(any.getChildren()));
        AtomicInteger count = new AtomicInteger(0);
        this.map = (collection, stream) -> collection.stream()
                .filter(box -> CollectionUtil.isNotEmpty(box.getChildren()))
                .flatMap(box -> box.getChildren()
                        .stream()
                        .map(any -> new StreamRecursive.Box<>(count.getAndIncrement(), box, any, childrenGetter)))
                .collect(Collectors.toList());
    }

    public StreamRecursive(Function<T, Collection<T>> childrenGetter) {
        this(childrenGetter, box -> (R) box.getSelf());
    }

    public Stream<R> exec(Collection<T> value) {
        AtomicInteger count = new AtomicInteger(0);
        List<StreamRecursive.Box<T, R>> list = value.stream()
                .map(any -> (StreamRecursive.Box<T, R>) new StreamRecursive.Box<>(count.getAndIncrement(), null, any, childrenGetter))
                .collect(Collectors.toList());
        return super.exec(list);
    }

    @Getter
    public static class Box<T, R> {
        /**
         * 下标,第一位为0
         */
        private Integer index;
        /**
         * 上级
         */
        private StreamRecursive.Box<T, R> parent;
        /**
         * 自身
         */
        private T self;
        /**
         * 当前结果的处理结果
         */
        @Setter
        private R ret;
        /**
         * 获取下级的方法
         */
        private Function<T, Collection<T>> childrenGetter;
        /**
         * 子级
         */
        private Collection<T> children;

        public Box(Integer index, StreamRecursive.Box<T, R> parent, T self, Function<T, Collection<T>> childrenGetter) {
            this.index = index;
            this.parent = parent;
            this.self = self;
            this.childrenGetter = childrenGetter;
        }

        /**
         * 缓存方式,减少获取方法的调用
         *
         * @return
         */
        public Collection<T> getChildren() {
            if (children == null) {
                children = childrenGetter.apply(self);
            }
            return children;
        }
    }
}
